<template>
  <div :class="wrapClasses">
    <template v-if="type !== 'textarea'">
      <div :class="[prefixCls + '-group-prepend']" v-if="prepend" v-show="slotReady">
        <slot name="prepend"></slot>
      </div>
      <i class="oolong-icon"
         :class="['oolong-icon-ios-close', prefixCls + '-icon', prefixCls + '-icon-clear' , prefixCls + '-icon-normal']"
         v-if="clearable && currentValue" @click="handleClear"></i>
      <i class="oolong-icon" :class="['oolong-icon-' + icon, prefixCls + '-icon', prefixCls + '-icon-normal']"
         v-else-if="icon" @click="handleIconClick"></i>
      <transition name="fade">
        <i class="oolong-icon oolong-icon-load-c oolong-load-loop"
           :class="[prefixCls + '-icon', prefixCls + '-icon-validate']" v-if="!icon"></i>
      </transition>
      <input
        :id="elementId"
        :autocomplete="autocomplete"
        :spellcheck="spellcheck"
        ref="input"
        :type="type"
        :class="inputClasses"
        :placeholder="placeholder"
        :disabled="disabled"
        :maxlength="maxlength"
        :readonly="readonly"
        :name="name"
        :value="currentValue"
        :number="number"
        :autofocus="autofocus"
        @keyup.enter="handleEnter"
        @keyup="handleKeyup"
        @keypress="handleKeypress"
        @keydown="handleKeydown"
        @focus="handleFocus"
        @blur="handleBlur"
        @input="handleInput"
        @change="handleChange">
      <div :class="[prefixCls + '-group-append']" v-if="append" v-show="slotReady">
        <slot name="append"></slot>
      </div>
    </template>
    <textarea
      v-else
      :id="elementId"
      :wrap="wrap"
      :autocomplete="autocomplete"
      :spellcheck="spellcheck"
      ref="textarea"
      :class="textareaClasses"
      :style="textareaStyles"
      :placeholder="placeholder"
      :disabled="disabled"
      :rows="rows"
      :maxlength="maxlength"
      :readonly="readonly"
      :name="name"
      :value="currentValue"
      :autofocus="autofocus"
      @keyup.enter="handleEnter"
      @keyup="handleKeyup"
      @keypress="handleKeypress"
      @keydown="handleKeydown"
      @focus="handleFocus"
      @blur="handleBlur"
      @input="handleInput">
        </textarea>
  </div>
</template>
<script>
import {findComponentUpward, oneOf} from '../../utils/assist';
import calcTextareaHeight from '../../utils/calcTextareaHeight';
import Emitter from '../../mixins/emitter';

const prefixCls = 'oolong-input';

export default {
  name: 'oolongInput',
  mixins: [Emitter],
  props: {
    type: {
      validator(value) {
        return oneOf(value, ['text', 'textarea', 'password', 'url', 'email', 'date']);
      },
      default: 'text'
    },
    value: {
      type: [String, Number],
      default: ''
    },
    size: {
      validator(value) {
        return oneOf(value, ['small', 'large', 'default']);
      }
    },
    placeholder: {
      type: String,
      default: ''
    },
    maxlength: {
      type: Number
    },
    disabled: {
      type: Boolean,
      default: false
    },
    icon: String,
    autosize: {
      type: [Boolean, Object],
      default: false
    },
    rows: {
      type: Number,
      default: 2
    },
    readonly: {
      type: Boolean,
      default: false
    },
    name: {
      type: String
    },
    number: {
      type: Boolean,
      default: false
    },
    autofocus: {
      type: Boolean,
      default: false
    },
    spellcheck: {
      type: Boolean,
      default: false
    },
    autocomplete: {
      validator(value) {
        return oneOf(value, ['on', 'off']);
      },
      default: 'off'
    },
    clearable: {
      type: Boolean,
      default: false
    },
    elementId: {
      type: String
    },
    wrap: {
      validator(value) {
        return oneOf(value, ['hard', 'soft']);
      },
      default: 'soft'
    }
  },
  data() {
    return {
      currentValue: this.value,
      prefixCls: prefixCls,
      prepend: true,
      append: true,
      slotReady: false,
      textareaStyles: {}
    };
  },
  computed: {
    wrapClasses() {
      return [
        `${prefixCls}-wrapper`,
        {
          [`${prefixCls}-wrapper-${this.size}`]: !!this.size,
          [`${prefixCls}-type`]: this.type,
          [`${prefixCls}-group`]: this.prepend || this.append,
          [`${prefixCls}-group-${this.size}`]: (this.prepend || this.append) && !!this.size,
          [`${prefixCls}-group-with-prepend`]: this.prepend,
          [`${prefixCls}-group-with-append`]: this.append,
          [`${prefixCls}-hide-icon`]: this.append// #554
        }
      ];
    },
    inputClasses() {
      return [
        `${prefixCls}`,
        {
          [`${prefixCls}-${this.size}`]: !!this.size,
          [`${prefixCls}-disabled`]: this.disabled
        }
      ];
    },
    textareaClasses() {
      return [
        `${prefixCls}`,
        {
          [`${prefixCls}-disabled`]: this.disabled
        }
      ];
    }
  },
  methods: {
    handleEnter(event) {
      this.$emit('on-enter', event);
    },
    handleKeydown(event) {
      this.$emit('on-keydown', event);
    },
    handleKeypress(event) {
      this.$emit('on-keypress', event);
    },
    handleKeyup(event) {
      this.$emit('on-keyup', event);
    },
    handleIconClick(event) {
      this.$emit('on-click', event);
    },
    handleFocus(event) {
      this.$emit('on-focus', event);
    },
    handleBlur(event) {
      this.$emit('on-blur', event);
      if (!findComponentUpward(this, ['DatePicker', 'TimePicker', 'Cascader', 'Search'])) {
        this.dispatch('FormItem', 'on-form-blur', this.currentValue);
      }
    },
    handleInput(event) {
      let value = event.target.value;
      if (this.number) value = Number.isNaN(Number(value)) ? value : Number(value);
      this.$emit('input', value);
      this.setCurrentValue(value);
      this.$emit('on-change', event);
    },
    handleChange(event) {
      this.$emit('on-input-change', event);
    },
    setCurrentValue(value) {
      if (value === this.currentValue) return;
      this.$nextTick(() => {
        this.resizeTextarea();
      });
      this.currentValue = value;
      if (!findComponentUpward(this, ['DatePicker', 'TimePicker', 'Cascader', 'Search'])) {
        this.dispatch('FormItem', 'on-form-change', value);
      }
    },
    resizeTextarea() {
      const autosize = this.autosize;
      if (!autosize || this.type !== 'textarea') {
        return false;
      }

      const minRows = autosize.minRows;
      const maxRows = autosize.maxRows;

      this.textareaStyles = calcTextareaHeight(this.$refs.textarea, minRows, maxRows);
    },
    focus() {
      if (this.type === 'textarea') {
        this.$refs.textarea.focus();
      } else {
        this.$refs.input.focus();
      }
    },
    blur() {
      if (this.type === 'textarea') {
        this.$refs.textarea.blur();
      } else {
        this.$refs.input.blur();
      }
    },
    handleClear() {
      const e = {target: {value: ''}};
      this.$emit('input', '');
      this.setCurrentValue('');
      this.$emit('on-change', e);
    }
  },
  watch: {
    value(val) {
      this.setCurrentValue(val);
    }
  },
  mounted() {
    if (this.type !== 'textarea') {
      this.prepend = this.$slots.prepend !== undefined;
      this.append = this.$slots.append !== undefined;
    } else {
      this.prepend = false;
      this.append = false;
    }
    this.slotReady = true;
    this.resizeTextarea();
  }
};
</script>
